package com.tbit.uqbike.webmanager.handler;

import com.alibaba.fastjson.JSON;
import com.tbit.common.entity.view.Result;
import com.tbit.uqbike.annos.CurrentLimit;

import com.tbit.uqbike.service.base.RedisService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 流量限制切面 - 降级
 * 基于接口参数入参维度，缓存接口执行结果
 *
 * @author <a href="mailto:zhang.zhiliang@tbit.com.cn">Zhang ZhiLiang</a>
 * @version 1.0
 * @see <a href="http://adsl1.tbit.com.cn:21490/pages/viewpage.action?pageId=82182491">订单号规范</a>
 * @since 2025/3/11
 */
@Data
@Slf4j
@Aspect
@Component
public class CurrentLimitAspect {
    private final RedisService redisService;

    // todo 可拓展基于令牌桶的限流 ， 基于缓存的降级 ， 以及超最大限度的熔断
    @Around("@within(com.tbit.uqbike.annos.CurrentLimit) || @annotation(com.tbit.uqbike.annos.CurrentLimit)")
    public Object proceed(ProceedingJoinPoint joinPoint) throws Throwable {
        CurrentLimit currentLimit = getCurrentLimit(joinPoint);
        String key = getMethodTag(joinPoint);
        String str = redisService.get(key);
        if (Objects.nonNull(str)){
            return JSON.parseObject(str, Result.class);
        }
        Object res = joinPoint.proceed();
        redisService.add(key,JSON.toJSONString(res), currentLimit.cacheTime(), TimeUnit.SECONDS);
        return res;
    }

    /**
     * 构造方法标签
     * 通过方法签名 + 入参的形式
     * @param joinPoint
     * @return
     */
    private String getMethodTag(ProceedingJoinPoint joinPoint){
        Object[] args = joinPoint.getArgs();
        Signature signature = joinPoint.getSignature();
        StringBuilder stringBuilder = new StringBuilder(JSON.toJSONString(signature).concat("$"));
        for (Object arg : args) {
            stringBuilder.append(JSON.toJSONString(arg)).append("#");
        }
        return stringBuilder.toString();
    }

    /**
     * 获取注解
     * @param joinPoint
     * @return
     */
    private CurrentLimit getCurrentLimit(ProceedingJoinPoint joinPoint){
        // 获取目标方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        // 先查找方法上的 @CurrentLimit
        CurrentLimit currentLimit = AnnotationUtils.findAnnotation(method, CurrentLimit.class);

        // 如果方法上没有 @CurrentLimit，则查找类上的
        if (currentLimit == null) {
            currentLimit = AnnotationUtils.findAnnotation(method.getDeclaringClass(), CurrentLimit.class);
        }
        return currentLimit;
    }

}
